package se.hjartstartarregistret.m;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

public class KmlParser {

	private static String AUTH_KEY = "6962b285-c2e3-4f08-a2c1-0cece7d7d432";

	// 54.8170742849,10.4383330345
	// 54.8170742849,24.2029876709
	// 69.1600289009,24.2029876709
	// 69.1600289009,10.4383330345
	// southWestLon + "," + southWestLat + "," + northEastLon + "," +
	// northEastLat;
	private static String BBOX = "10.4383330345,54.8170742849,24.2029876709,69.1600289009";

	static {
		try {
			KML_URL = new URL(
					"http://geo.hjartstartarregistret.se/geoserver/wms?authkey="
							+ AUTH_KEY
							+ "&LAYERS=HjaertstartarPositionsVy&TRANSPARENT=TRUE&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&STYLES=&FORMAT=kml&SRS=EPSG%3A4236&BBOX="
							+ BBOX + "&WIDTH=10&HEIGHT=10");
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(1);
		}
	}
	public static URL KML_URL;

	public static void main(String[] args) throws Exception {
		String json = parseKmlToJson();
		System.out.println(json);
		// PrintWriter out = new PrintWriter("/Users/fornwall/test.js");
		// out.println(json);
		System.out.println("LENGTH=" + json.length());
	}

	public static String parseKmlToJson() throws Exception {
		DocumentBuilder parser = DocumentBuilderFactory.newInstance()
				.newDocumentBuilder();

		HttpURLConnection connection = (HttpURLConnection) KML_URL
				.openConnection();
		connection.setConnectTimeout(5 * 60 * 1000);
		connection.setReadTimeout(5 * 60 * 1000);
		try (InputStream kmlIn = connection.getInputStream()) {
			InputSource is = new InputSource(new InputStreamReader(kmlIn,
					"utf-8"));

			Document doc = parser.parse(is);
			NodeList places = doc.getElementsByTagName("Placemark");
			StringBuilder out = new StringBuilder();

			out.append("[\n");
			outerLoop: for (int i = 0; i < places.getLength(); i++) {
				Element place = (Element) places.item(i);
				String latitude = ((Element) place.getElementsByTagName(
						"latitude").item(0)).getTextContent();
				String longitude = ((Element) place.getElementsByTagName(
						"longitude").item(0)).getTextContent();

				String description = ((Element) place.getElementsByTagName(
						"description").item(0)).getTextContent();
				description = description.replaceAll("&", "&amp;");
				Document descriptionDoc = parser
						.parse(new ByteArrayInputStream(new String("<doc>"
								+ description + "</doc>").getBytes("utf-8")));
				NodeList lis = descriptionDoc.getElementsByTagName("li");
				Map<String, String> attributeMap = new HashMap<String, String>();
				for (int j = 0; j < lis.getLength(); j++) {
					Element liElement = (Element) lis.item(j);
					String name = ((Element) liElement.getElementsByTagName(
							"span").item(0)).getTextContent();
					Element valueElement = ((Element) liElement
							.getElementsByTagName("span").item(1));
					if ("NuvarandeTillstaand".equals(name)
							&& !"Kontrollerad".equals(valueElement
									.getTextContent())) {

						continue outerLoop;
					} else if ("Adress".equals(name)
							|| "Placering".equals(name)
							|| "Innehavare".equals(name)
							|| "Vaaningsplan".equals(name)) {
						attributeMap.put(name.substring(0, 1).toLowerCase(),
								valueElement.getTextContent());
					} else if ("TillgaengligaTider".equals(name)) {
						NodeList tidList = valueElement
								.getElementsByTagName("tillgaengligTid");
						StringBuilder tillgaengligTid = new StringBuilder();
						Boolean open = false;
						for (int k = 0; k < tidList.getLength(); k++) {
							Element tidElement = (Element) tidList.item(k);
							String tidsperiod = ((Element) tidElement
									.getElementsByTagName("tidsperiod").item(0))
									.getTextContent();
							tillgaengligTid.append(tidsperiod);
							String dagar = ((Element) tidElement
									.getElementsByTagName("dagar").item(0))
									.getTextContent();
							tillgaengligTid.append(", " + dagar);
							String tider = ((Element) tidElement
									.getElementsByTagName("tider").item(0))
									.getTextContent();
							tillgaengligTid.append(", " + tider);
							tillgaengligTid.append("\n");
							open = open || isOpenNow(tidsperiod, dagar, tider);
						}
						attributeMap.put("o", String.valueOf(open));
						attributeMap.put("t", tillgaengligTid.toString());
					}
				}

				out.append("{ la: " + latitude + ", lo: " + longitude + ", \n");
				for (Map.Entry<String, String> entry : attributeMap.entrySet()) {
					out.append("\""
							+ entry.getKey()
							+ "\": \""
							+ StringEscapeUtils.escapeJavaScript(entry
									.getValue()) + "\",\n");

				}
				out.append("},\n");
			}
			out.append("];");
			return out.toString();
		}
	}

	private static boolean isOpenNow(String tidsPeriod, String dagar,
			String tider) {

		Date now = new Date();
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(now);
		try {
			if (!"Året runt".equals(tidsPeriod)) {
				if (tidsPeriod.indexOf("Mellan ") != 0) {
					return false;
				}
				tidsPeriod = tidsPeriod.replaceAll("Välj datum", "");
				Date tidsPeriodStart = fromSlashedToDate(
						tidsPeriod.split(" ")[1].split("-")[0], now);
				Date tidsPeriodEnd = fromSlashedToDate(
						tidsPeriod.split(" ")[1].split("-")[1], now);
				if (now.before(tidsPeriodStart) || now.after(tidsPeriodEnd))
					return false;
			}
			if (!"Alla dagar".equals(dagar)) {
				String[] parts = dagar.split(" till ");
				if (parts.length != 2) {
					return false;
				}
				int startDayNumber = dayToNumber(parts[0]);
				int endDayNumber = dayToNumber(parts[1]);
				Map<Integer, Boolean> includedDays = new HashMap<Integer, Boolean>();
				if (endDayNumber >= startDayNumber) {
					for (int day = startDayNumber; day <= endDayNumber; day++)
						includedDays.put(day, true);
				} else {
					return false;
				}
				if (includedDays.get(calendar.get(Calendar.DAY_OF_WEEK)) == null)
					return false;
			}
			if (!"Dygnet Runt".equals(tider)) {
				if (tider.indexOf("Från ") == -1
						|| tider.indexOf(" till ") == -1) {
					return false;
				}
				tider = tider.substring("Från ".length());
				String[] parts = tider.split(" till ");
				int startMinutes = timeStringToMinutes(parts[0]);
				int endMinutes = timeStringToMinutes(parts[1]);
				if (startMinutes > endMinutes) {
					endMinutes += 24 * 60;
				}
				int nowMinutes = calendar.get(Calendar.HOUR_OF_DAY) * 60
						+ calendar.get(Calendar.MINUTE);
				if (nowMinutes < startMinutes || nowMinutes > endMinutes)
					return false;
			}
		} catch (Exception e) {
			return false;
		}
		return true;
	}

	private static Date fromSlashedToDate(String tidsPeriod, Date now) {
		String month = "";
		String day = "";
		if (tidsPeriod.indexOf("/") != -1) {
			String[] parts = tidsPeriod.split("/");
			month = parts[1];
			day = parts[0];
		} else {
			tidsPeriod = tidsPeriod.replaceAll("/", "");
			month = tidsPeriod.substring(tidsPeriod.length() / 2);
			day = tidsPeriod.substring(0, tidsPeriod.length() / 2);
		}
		Calendar cal = Calendar.getInstance();
		cal.setTime(now);
		cal.set(Calendar.MONTH, Integer.parseInt(month));
		cal.set(Calendar.DAY_OF_MONTH, Integer.parseInt(day));
		return cal.getTime();
	}

	private static int dayToNumber(String dayString) {
		switch (dayString.toLowerCase()) {
		case "måndag":
			return 1;
		case "tisdag":
			return 2;
		case "onsdag":
			return 3;
		case "torsdag":
			return 4;
		case "fredag":
			return 5;
		case "lördag":
			return 6;
		case "söndag":
			return 0;
		default:
			return -1;
		}
	}

	private static int timeStringToMinutes(String timeString) {
		String[] parts = timeString.split(":");
		return Integer.parseInt(parts[0]) * 60 + Integer.parseInt(parts[1]);
	}
}
